﻿// --- Copyright (c) 2010 Steven Hartgers ---
// Copyright (C) 2010 Steven Hartgers All rights are reserved.
// Author contact: fiinix00/at\gmail.com
// ------------------------------------------------------------------------
// This program is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more detail
//  
// You should have received a copy of the GNU General Public License 
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Security.Cryptography;

namespace Hack
{
    public static class Math
    {
        /// <summary>
        /// Visual C# Kicks
        /// The C# function returns the distance between two points using Pythagorean Theorem.
        /// Platform: .NET Framework 2.0
        /// </summary>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <returns></returns>
        private static double DistanceBetween(PointF point1, PointF point2)
        {
            //pythagorean theorem c^2 = a^2 + b^2
            //thus c = square root(a^2 + b^2)
            double a = (double)(point2.X - point1.X);
            double b = (double)(point2.Y - point1.Y);

            return System.Math.Sqrt(a * a + b * b);
        }
        /// <summary>
        /// Author: ZIPCodeWorld
        /// Target platform: Platform: .NET Framework 2.0
        /// 
        /// Example Usage:
        ///   Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "M"));
        ///   Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "K"));
        ///   Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "N"));
        /// </summary>
        public static class LongitudeLattitude
        {
            public static double distance(double lat1, double lon1, double lat2, double lon2, char unit)
            {
                double theta = lon1 - lon2;
                double dist = System.Math.Sin(deg2rad(lat1)) * System.Math.Sin(deg2rad(lat2)) +
                              System.Math.Cos(deg2rad(lat1)) * System.Math.Cos(deg2rad(lat2)) *
                              System.Math.Cos(deg2rad(theta));
                dist = System.Math.Acos(dist);
                dist = rad2deg(dist);
                dist = dist * 60 * 1.1515;
                if (unit == 'K')
                {
                    dist = dist * 1.609344;
                }
                else if (unit == 'N')
                {
                    dist = dist * 0.8684;
                }
                return (dist);
            }
            public static double deg2rad(double deg)
            {
                return (deg * System.Math.PI / 180.0);
            }
            public static double rad2deg(double rad)
            {
                return (rad / System.Math.PI * 180.0);
            }
        }
        /// <summary>
        /// Author: Visual C# Kicks
        /// Platform: .NET Framework 2.0
        /// Using simple math we can convert between angles (in degrees) and XY-coordinate points. Useful when working with circle elements.
        /// </summary>
        public static class Degrees
        {

            /// <summary>
            /// Calculates a point that is at an angle from the origin (0 is to the right)
            /// </summary>
            public static PointF DegreesToXY(float degrees, float radius, Point origin)
            {
                PointF xy = new PointF();
                double radians = degrees * System.Math.PI / 180.0;

                xy.X = (float)System.Math.Cos(radians) * radius + origin.X;
                xy.Y = (float)System.Math.Sin(-radians) * radius + origin.Y;

                return xy;
            }

            /// <summary>
            /// Calculates the angle a point is to the origin (0 is to the right)
            /// </summary>
            public static float XYToDegrees(Point xy, Point origin)
            {
                int deltaX = origin.X - xy.X;
                int deltaY = origin.Y - xy.Y;

                double radAngle = System.Math.Atan2(deltaY, deltaX);
                double degreeAngle = radAngle * 180.0 / System.Math.PI;

                return (float)(180.0 - degreeAngle);
            }
        }
        public static class Combination
        {
            public static long Factorial(long x)
            {
                long fact = 1;
                long i = 1;
                while (i <= x)
                {
                    fact = fact * i;
                    i++;
                }
                return fact;
            }

            public static long Factorial(long x, long lowerBound)
            {
                long fact = 1;
                while (x >= 1 && x > lowerBound)
                {
                    fact *= x;
                    x--;
                }
                return fact;
            }

            public static long Choose(long n, long r)
            {
                return (long)((double)Factorial(n, System.Math.Max(n - r, r)) / (Factorial(System.Math.Min((long)n - r, (long)r))));//(n - r, r))));
            }
        }
        public struct Fraction
        {
            public int Numerator;
            public int Denominator;
            public static Fraction Zero = new Fraction(0, 0);

            public Fraction(int numerator, int denominator)
            {
                this.Numerator = numerator;
                this.Denominator = denominator;

                //If denominator negative...
                if (this.Denominator < 0)
                {
                    //...move the negative up to the numerator
                    this.Numerator = -this.Numerator;
                    this.Denominator = -this.Denominator;
                }
            }

            public Fraction(int numerator, Fraction denominator)
            {
                //divide the numerator by the denominator fraction
                this = new Fraction(numerator, 1) / denominator;
            }

            public Fraction(Fraction numerator, int denominator)
            {
                //multiply the numerator fraction by 1 over the denominator
                this = numerator * new Fraction(1, denominator);
            }

            public Fraction(Fraction fraction)
            {
                this.Numerator = fraction.Numerator;
                this.Denominator = fraction.Denominator;
            }


            private static int getGCD(int a, int b)
            {
                //Drop negative signs
                a = System.Math.Abs(a);
                b = System.Math.Abs(b);

                //Return the greatest common denominator between two integers
                while (a != 0 && b != 0)
                {
                    if (a > b)
                        a %= b;
                    else
                        b %= a;
                }

                if (a == 0)
                    return b;
                else
                    return a;
            }

            private static int getLCD(int a, int b)
            {
                //Return the Least Common Denominator between two integers
                return (a * b) / getGCD(a, b);
            }


            public Fraction ToDenominator(int targetDenominator)
            {
                //Multiply the fraction by a factor to make the denominator
                //match the target denominator
                Fraction modifiedFraction = this;

                //Cannot reduce to smaller denominators
                if (targetDenominator < this.Denominator)
                    return modifiedFraction;

                //The target denominator must be a factor of the current denominator
                if (targetDenominator % this.Denominator != 0)
                    return modifiedFraction;

                if (this.Denominator != targetDenominator)
                {
                    int factor = targetDenominator / this.Denominator;
                    modifiedFraction.Denominator = targetDenominator;
                    modifiedFraction.Numerator *= factor;
                }

                return modifiedFraction;
            }

            public Fraction GetReduced()
            {
                //Reduce the fraction to lowest terms
                Fraction modifiedFraction = this;

                //While the numerator and denominator share a greatest common denominator,
                //keep dividing both by it
                int gcd = 0;
                while (System.Math.Abs(gcd = getGCD(modifiedFraction.Numerator, modifiedFraction.Denominator)) != 1)
                {
                    modifiedFraction.Numerator /= gcd;
                    modifiedFraction.Denominator /= gcd;
                }

                //Make sure only a single negative sign is on the numerator
                if (modifiedFraction.Denominator < 0)
                {
                    modifiedFraction.Numerator = -this.Numerator;
                    modifiedFraction.Denominator = -this.Denominator;
                }

                return modifiedFraction;
            }

            public Fraction GetReciprocal()
            {
                //Flip the numerator and the denominator
                return new Fraction(this.Denominator, this.Numerator);
            }


            public static Fraction operator +(Fraction fraction1, Fraction fraction2)
            {
                //Check if either fraction is zero
                if (fraction1.Denominator == 0)
                    return fraction2;
                else if (fraction2.Denominator == 0)
                    return fraction1;

                //Get Least Common Denominator
                int lcd = getLCD(fraction1.Denominator, fraction2.Denominator);

                //Transform the fractions
                fraction1 = fraction1.ToDenominator(lcd);
                fraction2 = fraction2.ToDenominator(lcd);

                //Return sum
                return new Fraction(fraction1.Numerator + fraction2.Numerator, lcd).GetReduced();
            }

            public static Fraction operator -(Fraction fraction1, Fraction fraction2)
            {
                //Get Least Common Denominator
                int lcd = getLCD(fraction1.Denominator, fraction2.Denominator);

                //Transform the fractions
                fraction1 = fraction1.ToDenominator(lcd);
                fraction2 = fraction2.ToDenominator(lcd);

                //Return difference
                return new Fraction(fraction1.Numerator - fraction2.Numerator, lcd).GetReduced();
            }

            public static Fraction operator *(Fraction fraction1, Fraction fraction2)
            {
                int numerator = fraction1.Numerator * fraction2.Numerator;
                int denomenator = fraction1.Denominator * fraction2.Denominator;

                return new Fraction(numerator, denomenator).GetReduced();
            }

            public static Fraction operator /(Fraction fraction1, Fraction fraction2)
            {
                return new Fraction(fraction1 * fraction2.GetReciprocal()).GetReduced();
            }


            public double ToDouble()
            {
                return (double)this.Numerator / this.Denominator;
            }

            public override string ToString()
            {
                return Numerator + "/" + Denominator;
            }
        }

        /// <summary>
        /// Author: VCSKicks
        /// Platform: .NET Framework 2.0
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static int CryptoRandom(int min, int max)
        {
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            byte[] buffer = new byte[4];

            rng.GetBytes(buffer);
            int result = BitConverter.ToInt32(buffer, 0);

            return new Random(result).Next(min, max);
        }

        /// <summary>
        /// quadratic equation Ax^2 + Bx + C = 0
        /// </summary>
        public class QuadraticEquation
        {
            // ******************************************************************
            // A quadratic equation always has two roots
            // ******************************************************************
            private struct Root
            {
                public double R1_Re;
                public double R1_Im;
                public double R2_Re;
                public double R2_Im;
            }
            private Root MyRoot;

            // ******************************************************************
            // Keep the coefficient private we get and set them via properties
            // ******************************************************************
            private double cA = 0.0;
            private double cB = 0.0;
            private double cC = 0.0;

            // ******************************************************************
            // Constructors
            // ******************************************************************
            public QuadraticEquation() { }

            public QuadraticEquation(double A, double B, double C)
            {
                cA = A;
                cB = B;
                cC = C;
            }

            // ******************************************************************
            // Properties
            // ******************************************************************
            public double Acoefficient { get { return cA; } set { cA = value; } }
            public double Bcoefficient { get { return cB; } set { cB = value; } }
            public double Ccoefficient { get { return cC; } set { cC = value; } }
            public double Root1RealPart { get { return MyRoot.R1_Re; } }
            public double Root1ImagPart { get { return MyRoot.R1_Im; } }
            public double Root2RealPart { get { return MyRoot.R2_Re; } }
            public double Root2ImagPart { get { return MyRoot.R2_Im; } }

            // ******************************************************************
            // Return the discriminant b*b-4*a*c
            // ******************************************************************
            public double Discriminant()
            {
                return cB * cB - 4 * cA * cC;
            }

            // ******************************************************************
            // Solve the equation and fill the roots struct with the results
            // ******************************************************************
            public void Solve()
            {
                // Preliminary calculations to avoid numbercrunching overhead
                double D = Discriminant();
                double twoA = cA + cA;
                double B2A = -cB / twoA;

                if (D == 0)             // roots are equal and real
                {
                    MyRoot.R1_Re = MyRoot.R2_Re = B2A;
                    MyRoot.R1_Im = MyRoot.R2_Im = 0.0;
                }
                else if (D > 0)         // roots are distinct and real
                {
                    MyRoot.R1_Re = B2A + System.Math.Sqrt(D) / twoA;
                    MyRoot.R2_Re = B2A - System.Math.Sqrt(D) / twoA;
                    MyRoot.R1_Im = 0.0;
                    MyRoot.R2_Im = 0.0;
                }
                else if (D < 0)         // no real roots, 2 complex conjugate roots
                {
                    MyRoot.R1_Re = MyRoot.R2_Re = B2A;
                    D = -D;
                    MyRoot.R1_Im = System.Math.Sqrt(D) / twoA;
                    MyRoot.R2_Im = -System.Math.Sqrt(D) / twoA;
                }
            }
        }
        public static class Weight
        {
            public static double KgToPound(double kg)
            {
                return kg * 2.2;
            }
            public static double LbsToKg(double lbs)
            {
                return lbs / 2.2;
            }
        }
        public static class Length
        {
            public static double InchToCm(double inch)
            {
                return inch * 2.54;
            }
            public static double CmToInch(double cm)
            {
                return cm * 0.3937008;
            }
        }
        public static class WeatherDegrees
        {
            public static double CelsiusToFahrenheit(double celsius)
            {
                return celsius * 9 / 5 + 32;
            }
            public static double FahrenheitToCelsius(double fahrenheit)
            {
                return (fahrenheit - 32) * 5 / 9;
            }

        }
    }
}
